home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 2 / AACD 2.iso / AACD / Online / Socks5 / src / server / tracer.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-03-10  |  10.3 KB  |  325 lines

  1. /* Copyright (c) 1995-1999 NEC USA, Inc.  All rights reserved.               */
  2. /*                                                                           */
  3. /* The redistribution, use and modification in source or binary forms of     */
  4. /* this software is subject to the conditions set forth in the copyright     */
  5. /* document ("Copyright") included with this distribution.                   */
  6.  
  7. /*
  8.  * $Id: tracer.c,v 1.40.4.5 1999/02/03 22:35:50 steve Exp $
  9.  */
  10.  
  11. #include "socks5p.h"
  12. #include "daemon.h"
  13. #include "protocol.h"
  14. #include "validate.h"
  15. #include "sident.h"
  16. #include "msgids.h"
  17. #include "flow.h"
  18. #include "info.h"
  19. #include "log.h"
  20. #include "msg.h"
  21. #include "s2s.h"
  22.  
  23. struct ptinfo {
  24.     S5IOInfo iio, oio, pio;
  25.     int stopchild, childpid, exitval, msgsent;
  26.     char tmpmsg[GENERICBUFSIZE], idtentry[IDTENTRY_SIZE];
  27.     char *packetbuf;
  28. };
  29.  
  30. typedef struct ptinfo PTInfo;
  31.  
  32. #define CommandName(x) (((x)->peerCommand == SOCKS_PING)?"PING":"Traceroute")
  33.  
  34. #ifndef REPLYTIMEOUT
  35. #define REPLYTIMEOUT 60
  36. #endif
  37.  
  38. static int Popen(S5LinkInfo *pri, PTInfo *ptinfo) {
  39.     S5IOHandle pds[2];
  40.  
  41. #ifndef TROUTEPROG
  42.     if (pri->peerCommand == SOCKS_TRACER) {
  43.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "%s: No real program to exec", CommandName(pri));
  44.     return -1;
  45.     }
  46. #endif
  47.  
  48. #ifndef PINGPROG
  49.     if (pri->peerCommand != SOCKS_TRACER) {
  50.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "%s: No real program to exec", CommandName(pri));
  51.     return -1;
  52.     }
  53. #endif
  54.  
  55.     if (pipe(pds) < 0) {
  56.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "%s pipe failed: %m", CommandName(pri));
  57.     return -1;
  58.     }
  59.  
  60.     if ((ptinfo->childpid = fork()) < 0) {
  61.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "%s fork failed: %m", CommandName(pri));
  62.     close(pds[0]);
  63.     close(pds[1]);
  64.     return -1;
  65.     }
  66.  
  67.     S5BufSetupContext(&ptinfo->pio);
  68.     ptinfo->pio.fd        = pds[0];
  69.  
  70.     if (ptinfo->childpid == 0) {
  71.     close(pds[0]);
  72.     if (dup2(pds[1], STDOUT_FILENO) < 0) _exit(-1);
  73.     if (dup2(pds[1], STDERR_FILENO) < 0) _exit(-1);
  74.     close(pds[1]);
  75.  
  76. #ifdef TROUTEPROG
  77.     if ((pri->peerCommand == SOCKS_TRACER)) {
  78.         int verbose = pri->peerReserved & SOCKS5_FLAG_VERBOSE;
  79.         int noname  = pri->peerReserved & SOCKS5_FLAG_NONAME;
  80.         
  81.         if (pri->nextVersion) {
  82.             if (noname) execlp(TROUTEPROG, "traceroute", "-n", (verbose?"-v":pri->sckName), verbose?pri->sckName:NULL, NULL);
  83.             else        execlp(TROUTEPROG, "traceroute",       (verbose?"-v":pri->sckName), verbose?pri->sckName:NULL, NULL);
  84.         } else {
  85.             if (noname) execlp(TROUTEPROG, "traceroute", "-n", (verbose?"-v":pri->dstName), verbose?pri->dstName:NULL, NULL);
  86.             else        execlp(TROUTEPROG, "traceroute",       (verbose?"-v":pri->dstName), verbose?pri->dstName:NULL, NULL);
  87.         }
  88.     } 
  89. #endif
  90.  
  91. #ifdef PINGPROG
  92.     if (!(pri->peerCommand == SOCKS_TRACER)) {
  93.         execlp(PINGPROG, "ping", pri->dstName, NULL);
  94.     }        
  95. #endif
  96.  
  97.     _exit(0);
  98.     }
  99.  
  100.     ptinfo->stopchild  = 1;
  101.     close(pds[1]);
  102.  
  103.     return 0;
  104. }
  105.  
  106. static int InitProxy(S5LinkInfo *pri, PTInfo *ptinfo) {
  107.     S5NetAddr junk;
  108.  
  109.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "%s Using proxy (version %d) %s:%d", CommandName(pri), (int)pri->nextVersion, ADDRANDPORT(&pri->sckAddr));
  110.  
  111.     if ((ptinfo->oio.fd = socket(AF_INET, SOCK_STREAM, 0)) == S5InvalidIOHandle) {
  112.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "%s socket failed: %m", CommandName(pri));
  113.     return -1;
  114.     }
  115.  
  116.     if (S5SExchangeProtocol(&ptinfo->iio, &ptinfo->oio, pri, ptinfo->idtentry, &pri->dstAddr, &junk) == 0) {
  117.     return 0;
  118.     }
  119.  
  120.     CLOSESOCKET(ptinfo->oio.fd);
  121.     ptinfo->oio.fd = S5InvalidIOHandle;
  122.     return -1;
  123. }
  124.  
  125. static void WaitChild(PTInfo *coption) {
  126.     int wstatus;
  127.  
  128.     if (!coption->stopchild) return;
  129. #ifdef HAVE_WAITPID
  130.     waitpid(coption->childpid, &wstatus, 0);
  131. #else
  132.     wait4(coption->childpid, &wstatus, 0, NULL);
  133. #endif
  134.  
  135.     close(coption->pio.fd);
  136.     coption->pio.fd    = S5InvalidIOHandle;
  137.     coption->stopchild = 0;
  138.     coption->childpid  = 0;
  139. }    
  140.  
  141. static int PTRecvPkt(S5Packet *packet, S5LinkInfo *pri, PTInfo *coption, int *dir) {
  142.     int rv = EXIT_ERR, savedir;
  143.  
  144.     if (!coption) {
  145.     return EXIT_ERR;
  146.     } else if (coption->pio.fd != S5InvalidIOHandle && !coption->msgsent) {
  147.     packet->data = (char *)malloc(GENERICBUFSIZE * sizeof(char));
  148.     packet->len  = GENERICBUFSIZE;
  149.     packet->off  = 0;
  150.     
  151.     if (packet->data) {
  152.         strcpy(packet->data, coption->tmpmsg);
  153.         packet->off = rv = strlen(coption->tmpmsg);
  154.         *dir = S5_DIRECTION_IN;
  155.         coption->msgsent = 1;
  156.     } else return EXIT_ERR;
  157.     } else {
  158.     if (coption->pio.fd != S5InvalidIOHandle) {
  159.         for (;;) {
  160.             savedir = *dir;
  161.             rv = S5TcpFlowRecv(&coption->iio, &coption->pio, packet, dir);
  162.  
  163.             if (rv == 0 && *dir == S5_DIRECTION_IN) {
  164.                 /* The pipe is closed (command done) as just the first part   */
  165.                 /* of a 2 part process by closing the pipe and go to the      */
  166.                 /* second part to get dome "real" data...                     */
  167.                 WaitChild(coption);
  168.                 *dir = savedir;
  169.              if (pri->nextVersion) rv = S5TcpFlowRecv(&coption->iio, &coption->oio, packet, dir);
  170.             } else if (rv > 0 && *dir == S5_DIRECTION_OUT) {
  171.                 /* If the client sends anything, it is a message to stop.     */
  172.                 if (coption->stopchild) {
  173.             kill(coption->childpid, SIGINT);
  174.                     coption->stopchild = 0;
  175.             }
  176.                 *dir = savedir;
  177.             packet->off = 0;
  178.             continue;
  179.             }
  180.             break;
  181.         }
  182.     } else rv = S5TcpFlowRecv(&coption->iio, &coption->oio, packet, dir);
  183.     }
  184.  
  185.     if (rv < 0) coption->exitval = EXIT_ERR;
  186.     else        coption->exitval = EXIT_OK;
  187.  
  188.     if (packet->data) coption->packetbuf = packet->data;
  189.     return rv;
  190. }
  191.  
  192. static int PTSendPkt(S5Packet *packet, S5LinkInfo *pri, PTInfo *coption, int *dir) {
  193.     int rv;
  194.     
  195.     if (!coption) return -1;
  196.  
  197.     rv = S5TcpFlowSend(&coption->iio, &coption->oio, packet, dir);
  198.     
  199.     if (rv < 0) coption->exitval = EXIT_ERR;
  200.     else        coption->exitval = EXIT_OK;
  201.     
  202.     return rv;
  203. }
  204.  
  205. static int PTClose(S5LinkInfo *linkinfo, PTInfo *coption) {
  206.     if (!coption) return -1;
  207.     
  208.     if (coption->childpid > 0 && coption->stopchild) {
  209.         kill(coption->childpid, SIGINT);
  210.     WaitChild(coption);
  211.     }
  212.  
  213.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_INFO, MSGID_SERVER_PT_END, "%s Proxy Terminated: %s (%s to %s) for user %s: %d bytes out, %d bytes in",
  214.     CommandName(linkinfo), (coption->exitval == EXIT_ERR)?"Abnormal":"Normal",
  215.     linkinfo->srcName, linkinfo->dstName, linkinfo->srcUser,
  216.     linkinfo->outbc,    linkinfo->inbc);
  217.     
  218.     S5BufCleanContext(&coption->oio);
  219.     S5BufCleanContext(&coption->iio);
  220.     S5BufCleanContext(&coption->pio);
  221.  
  222.     if (coption->packetbuf) free(coption->packetbuf);
  223.     RemoveIdentEntry(coption->idtentry);
  224.     free(coption);
  225.     return 0;
  226. }
  227.  
  228. int PTSetup(S5IOInfo *ioinfo, S5LinkInfo *linkinfo, S5CommandInfo *cinfo) {
  229.     int turnon = 1, rval = EXIT_ERR;
  230.     PTInfo *ptinfo = NULL;
  231.     
  232.     if (ResolveNames(linkinfo) < 0) {
  233.     goto cleanup;
  234.     }
  235.  
  236.     if (!(cinfo->option = (void *)(ptinfo = (PTInfo *)malloc(sizeof(PTInfo))))) {
  237.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "%s malloc failed", CommandName(linkinfo));
  238.     goto cleanup;
  239.     }
  240.  
  241.     ptinfo->exitval       = EXIT_OK;
  242.     ptinfo->msgsent       = 0;
  243.     ptinfo->stopchild     = 0;
  244.     ptinfo->childpid      = 0;
  245.     ptinfo->iio           = *ioinfo;
  246.     ptinfo->packetbuf     = NULL;
  247.     InitIdentEntry(ptinfo->idtentry);
  248.  
  249.     S5BufSetupContext(&ptinfo->oio);
  250.     S5BufSetupContext(&ptinfo->pio);
  251.  
  252.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_INFO, MSGID_SERVER_PT_START, "%s Proxy Request: (%s to %s) for user %s",
  253.         CommandName(linkinfo), linkinfo->srcName, linkinfo->dstName, linkinfo->srcUser);
  254.  
  255.     if (Authorize(linkinfo, 0) != AUTH_OK) {
  256.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, MSGID_SERVER_PT_AUTH, "%s Authorization failed", CommandName(linkinfo));
  257.     rval = EXIT_AUTH;
  258.     goto cleanup;
  259.     }
  260.     
  261.     if (linkinfo->nextVersion && InitProxy(linkinfo, ptinfo) < 0) {
  262.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "%s Init Proxy Failed", CommandName(linkinfo));
  263.     goto cleanup;
  264.     }
  265.  
  266.     if (linkinfo->peerCommand == SOCKS_TRACER) {
  267.     sprintf(ptinfo->tmpmsg, "\nTraceroute to %s...\n", linkinfo->nextVersion?linkinfo->sckName:linkinfo->dstName);
  268.     } else {
  269.     ptinfo->msgsent = 1;
  270.     }
  271.  
  272.     if (!linkinfo->nextVersion || linkinfo->peerCommand == SOCKS_TRACER) {
  273.     if (Popen(linkinfo, ptinfo) < 0) {
  274.         if (!linkinfo->nextVersion) {
  275.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "%s Failed to open pipe for real command", CommandName(linkinfo));
  276.         goto cleanup;
  277.         }
  278.  
  279.         if (linkinfo->peerCommand == SOCKS_TRACER) {
  280.         strcat(ptinfo->tmpmsg, "Traceroute not available on this host\n");
  281.         }
  282.     }
  283.     }
  284.  
  285.     /* Set out of band data inline, since we won't be dealing with it....    */
  286.     if (setsockopt(ptinfo->iio.fd, SOL_SOCKET, SO_OOBINLINE, (char *)&turnon, sizeof(int)) < 0) {
  287.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "%s Setup: Failed to inline out-of-band data: %m", CommandName(linkinfo));
  288.     rval = EXIT_NETERR;
  289.     goto cleanup;
  290.     }
  291.  
  292.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_INFO, MSGID_SERVER_PT_ESTAB, "%s Proxy Established: (%s to %s) for user %s",
  293.         CommandName(linkinfo), linkinfo->srcName, linkinfo->dstName, linkinfo->srcUser);
  294.     if (lsSendResponse(ptinfo->iio.fd, &ptinfo->iio, &linkinfo->dstAddr, linkinfo->peerVersion, 0, 0, NULL) < 0) {
  295.     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "Client closed connection");
  296.     rval = EXIT_NETERR;
  297.     goto cleanup;
  298.     }
  299.     recv_sigio(ioinfo->fd);
  300.  
  301.     cinfo->recvpkt = (int (*)(S5Packet *, S5LinkInfo *, void *, int *))PTRecvPkt;
  302.     cinfo->sendpkt = (int (*)(S5Packet *, S5LinkInfo *, void *, int *))PTSendPkt;
  303.     cinfo->clean   = (int (*)(S5LinkInfo *, void *))PTClose;
  304.     return EXIT_OK;
  305.  
  306.   cleanup:
  307.     if (rval != EXIT_NETERR) lsSendResponse(ioinfo->fd, ioinfo, &linkinfo->dstAddr, linkinfo->peerVersion, 1, 0, NULL);
  308.  
  309.     if (ptinfo != NULL) {
  310.     ptinfo->exitval = EXIT_ERR;
  311.         PTClose(linkinfo, ptinfo);
  312.     } else {
  313.         S5LogUpdate(S5LogDefaultHandle, S5_LOG_INFO, MSGID_SERVER_PT_END, "%s Proxy Terminated: %s (%s to %s) for user %s: %d bytes out, %d bytes in",
  314.             CommandName(linkinfo), "Abnormal",
  315.             linkinfo->srcName, linkinfo->dstName, linkinfo->srcUser,
  316.             linkinfo->outbc,    linkinfo->inbc);
  317.  
  318.         S5BufCleanContext(ioinfo);
  319.     }
  320.  
  321.     cinfo->option = NULL;
  322.     if (rval == EXIT_OK) rval = EXIT_ERR;
  323.     return rval;
  324. }
  325.